home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / winterp-1.13 / src-server / xlisp / xlcont.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-04  |  29.9 KB  |  1,455 lines

  1. /* -*-C-*-
  2. ********************************************************************************
  3. *
  4. * File:         xlcont
  5. * RCS:          $Header: xlcont.c,v 1.6 91/03/24 22:24:27 mayer Exp $
  6. * Description:  xlisp special forms
  7. * Author:       David Michael Betz
  8. * Created:      
  9. * Modified:     Fri Oct  4 03:37:41 1991 (Niels Mayer) mayer@hplnpm
  10. * Language:     C
  11. * Package:      N/A
  12. * Status:       X11r5 contrib tape release
  13. *
  14. * WINTERP Copyright 1989, 1990, 1991 Hewlett-Packard Company (by Niels Mayer).
  15. * XLISP version 2.1, Copyright (c) 1989, by David Betz.
  16. *
  17. * Permission to use, copy, modify, distribute, and sell this software and its
  18. * documentation for any purpose is hereby granted without fee, provided that
  19. * the above copyright notice appear in all copies and that both that
  20. * copyright notice and this permission notice appear in supporting
  21. * documentation, and that the name of Hewlett-Packard and David Betz not be
  22. * used in advertising or publicity pertaining to distribution of the software
  23. * without specific, written prior permission.  Hewlett-Packard and David Betz
  24. * make no representations about the suitability of this software for any
  25. * purpose. It is provided "as is" without express or implied warranty.
  26. *
  27. * HEWLETT-PACKARD AND DAVID BETZ DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  28. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  29. * IN NO EVENT SHALL HEWLETT-PACKARD NOR DAVID BETZ BE LIABLE FOR ANY SPECIAL,
  30. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  31. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  32. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  33. * PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * See ./winterp/COPYRIGHT for information on contacting the authors.
  36. * Please send modifications, improvements and bugfixes to mayer@hplabs.hp.com
  37. * Post XLISP-specific questions/information to the newsgroup comp.lang.lisp.x
  38. *
  39. ********************************************************************************
  40. */
  41. static char rcs_identity[] = "@(#)$Header: xlcont.c,v 1.6 91/03/24 22:24:27 mayer Exp $";
  42.  
  43.  
  44. #include "xlisp.h"
  45.  
  46. /* external variables */
  47. extern LVAL xlenv,xlfenv,xldenv,xlvalue;
  48. extern LVAL s_setf,s_car,s_cdr,s_nth,s_aref,s_get;
  49. extern LVAL s_svalue,s_sfunction,s_splist;
  50. extern LVAL s_lambda,s_macro;
  51. extern LVAL s_comma,s_comat;
  52. extern LVAL s_unbound;
  53. extern LVAL true;
  54.  
  55. /* external routines */
  56. extern LVAL makearglist();
  57.  
  58. /* forward declarations */
  59. LOCAL FORWARD LVAL bquote1();    /* NPM: changed this to LOCAL */
  60. LOCAL FORWARD LVAL let();    /* NPM: changed this to LOCAL */
  61. LOCAL FORWARD LVAL flet();    /* NPM: changed this to LOCAL */
  62. LOCAL FORWARD LVAL prog();    /* NPM: changed this to LOCAL */
  63. LOCAL FORWARD LVAL progx();    /* NPM: changed this to LOCAL */
  64. LOCAL FORWARD LVAL doloop();    /* NPM: changed this to LOCAL */
  65. LOCAL FORWARD LVAL evarg();    /* NPM: changed this to LOCAL */
  66. LOCAL FORWARD LVAL match();    /* NPM: changed this to LOCAL */
  67. LOCAL FORWARD LVAL evmatch();    /* NPM: changed this to LOCAL */
  68.  
  69. /* dummy node type for a list */
  70. #define LIST    -1
  71.  
  72. /* xquote - special form 'quote' */
  73. LVAL xquote()
  74. {
  75.     LVAL val;
  76.     val = xlgetarg();
  77.     xllastarg();
  78.     return (val);
  79. }
  80.  
  81. /* xfunction - special form 'function' */
  82. LVAL xfunction()
  83. {
  84.     LVAL val;
  85.  
  86.     /* get the argument */
  87.     val = xlgetarg();
  88.     xllastarg();
  89.  
  90.     /* create a closure for lambda expressions */
  91.     if (consp(val) && car(val) == s_lambda && consp(cdr(val)))
  92.     val = xlclose(NIL,s_lambda,car(cdr(val)),cdr(cdr(val)),xlenv,xlfenv);
  93.  
  94.     /* otherwise, get the value of a symbol */
  95.     else if (symbolp(val))
  96.     val = xlgetfunction(val);
  97.  
  98.     /* otherwise, its an error */
  99.     else
  100.     xlerror("not a function",val);
  101.  
  102.     /* return the function */
  103.     return (val);
  104. }
  105.  
  106. /* xbquote - back quote special form */
  107. LVAL xbquote()
  108. {
  109.     LVAL expr;
  110.  
  111.     /* get the expression */
  112.     expr = xlgetarg();
  113.     xllastarg();
  114.  
  115.     /* fill in the template */
  116.     return (bquote1(expr));
  117. }
  118.  
  119. /* bquote1 - back quote helper function */
  120. LOCAL LVAL bquote1(expr)
  121.   LVAL expr;
  122. {
  123.     LVAL val,list,last,new;
  124.  
  125.     /* handle atoms */
  126.     if (atom(expr))
  127.     val = expr;
  128.  
  129.     /* handle (comma <expr>) */
  130.     else if (car(expr) == s_comma) {
  131.     if (atom(cdr(expr)))
  132.         xlfail("bad comma expression");
  133.     val = xleval(car(cdr(expr)));
  134.     }
  135.  
  136.     /* handle ((comma-at <expr>) ... ) */
  137.     else if (consp(car(expr)) && car(car(expr)) == s_comat) {
  138.     xlstkcheck(2);
  139.     xlsave(list);
  140.     xlsave(val);
  141.     if (atom(cdr(car(expr))))
  142.         xlfail("bad comma-at expression");
  143.     list = xleval(car(cdr(car(expr))));
  144.     for (last = NIL; consp(list); list = cdr(list)) {
  145.         new = consa(car(list));
  146.         if (last)
  147.         rplacd(last,new);
  148.         else
  149.         val = new;
  150.         last = new;
  151.     }
  152.     if (last)
  153.         rplacd(last,bquote1(cdr(expr)));
  154.     else
  155.         val = bquote1(cdr(expr));
  156.     xlpopn(2);
  157.     }
  158.  
  159.     /* handle any other list */
  160.     else {
  161.     xlsave1(val);
  162.     val = consa(NIL);
  163.     rplaca(val,bquote1(car(expr)));
  164.     rplacd(val,bquote1(cdr(expr)));
  165.     xlpop();
  166.     }
  167.  
  168.     /* return the result */
  169.     return (val);
  170. }
  171.  
  172. /* xlambda - special form 'lambda' */
  173. LVAL xlambda()
  174. {
  175.     LVAL fargs,arglist,val;
  176.  
  177.     /* get the formal argument list and function body */
  178.     xlsave1(arglist);
  179.     fargs = xlgalist();
  180.     arglist = makearglist(xlargc,xlargv);
  181.  
  182.     /* create a new function definition */
  183.     val = xlclose(NIL,s_lambda,fargs,arglist,xlenv,xlfenv);
  184.  
  185.     /* restore the stack and return the closure */
  186.     xlpop();
  187.     return (val);
  188. }
  189.  
  190. /* xgetlambda - get the lambda expression associated with a closure */
  191. LVAL xgetlambda()
  192. {
  193.     LVAL closure;
  194.     closure = xlgaclosure();
  195.     return (cons(gettype(closure),
  196.                  cons(getlambda(closure),getbody(closure))));
  197. }
  198.  
  199. /* xsetq - special form 'setq' */
  200. LVAL xsetq()
  201. {
  202.     LVAL sym,val;
  203.  
  204.     /* handle each pair of arguments */
  205.     for (val = NIL; moreargs(); ) {
  206.     sym = xlgasymbol();
  207.     val = xleval(nextarg());
  208.     xlsetvalue(sym,val);
  209.     }
  210.  
  211.     /* return the result value */
  212.     return (val);
  213. }
  214.  
  215. /* xpsetq - special form 'psetq' */
  216. LVAL xpsetq()
  217. {
  218.     LVAL plist,sym,val;
  219.  
  220.     /* protect some pointers */
  221.     xlsave1(plist);
  222.  
  223.     /* handle each pair of arguments */
  224.     for (val = NIL; moreargs(); ) {
  225.     sym = xlgasymbol();
  226.     val = xleval(nextarg());
  227.     plist = cons(cons(sym,val),plist);
  228.     }
  229.  
  230.     /* do parallel sets */
  231.     for (; plist; plist = cdr(plist))
  232.     xlsetvalue(car(car(plist)),cdr(car(plist)));
  233.  
  234.     /* restore the stack */
  235.     xlpop();
  236.  
  237.     /* return the result value */
  238.     return (val);
  239. }
  240.  
  241. /* xsetf - special form 'setf' */
  242. LVAL xsetf()
  243. {
  244.     LVAL place,value;
  245.  
  246.     /* protect some pointers */
  247.     xlsave1(value);
  248.  
  249.     /* handle each pair of arguments */
  250.     while (moreargs()) {
  251.  
  252.     /* get place and value */
  253.     place = xlgetarg();
  254.     value = xleval(nextarg());
  255.  
  256.     /* expand macros in the place form */
  257.     if (consp(place))
  258.         place = xlexpandmacros(place);
  259.     
  260.     /* check the place form */
  261.     if (symbolp(place))
  262.         xlsetvalue(place,value);
  263.     else if (consp(place))
  264.         placeform(place,value);
  265.     else
  266.         xlfail("bad place form");
  267.     }
  268.  
  269.     /* restore the stack */
  270.     xlpop();
  271.  
  272.     /* return the value */
  273.     return (value);
  274. }
  275.  
  276. /* placeform - handle a place form other than a symbol */
  277. #ifdef WINTERP
  278. placeform(place,value)        /* needed by w_resources.c:Wres_GetValues_ArgList_To_Lisp */
  279. #else
  280. LOCAL placeform(place,value)
  281. #endif
  282.   LVAL place,value;
  283. {
  284.     LVAL fun,arg1,arg2;
  285.     int i;
  286.  
  287.     /* check the function name */
  288.     if ((fun = match(SYMBOL,&place)) == s_get) {
  289.     xlstkcheck(2);
  290.     xlsave(arg1);
  291.     xlsave(arg2);
  292.     arg1 = evmatch(SYMBOL,&place);
  293.     arg2 = evmatch(SYMBOL,&place);
  294.     if (place) toomany(place);
  295.     xlputprop(arg1,value,arg2);
  296.     xlpopn(2);
  297.     }
  298.     else if (fun == s_svalue) {
  299.     arg1 = evmatch(SYMBOL,&place);
  300.     if (place) toomany(place);
  301.     setvalue(arg1,value);
  302.     }
  303.     else if (fun == s_sfunction) {
  304.     arg1 = evmatch(SYMBOL,&place);
  305.     if (place) toomany(place);
  306.     setfunction(arg1,value);
  307.     }
  308.     else if (fun == s_splist) {
  309.     arg1 = evmatch(SYMBOL,&place);
  310.     if (place) toomany(place);
  311.     setplist(arg1,value);
  312.     }
  313.     else if (fun == s_car) {
  314.     arg1 = evmatch(CONS,&place);
  315.     if (place) toomany(place);
  316.     rplaca(arg1,value);
  317.     }
  318.     else if (fun == s_cdr) {
  319.     arg1 = evmatch(CONS,&place);
  320.     if (place) toomany(place);
  321.     rplacd(arg1,value);
  322.     }
  323.     else if (fun == s_nth) {
  324.     xlsave1(arg1);
  325.     arg1 = evmatch(FIXNUM,&place);
  326.     arg2 = evmatch(LIST,&place);
  327.     if (place) toomany(place);
  328.     for (i = (int)getfixnum(arg1); i > 0 && consp(arg2); --i)
  329.         arg2 = cdr(arg2);
  330.     if (consp(arg2))
  331.         rplaca(arg2,value);
  332.     xlpop();
  333.     }
  334.     else if (fun == s_aref) {
  335.     xlsave1(arg1);
  336.     arg1 = evmatch(VECTOR,&place);
  337.     arg2 = evmatch(FIXNUM,&place); i = (int)getfixnum(arg2);
  338.     if (place) toomany(place);
  339.     if (i < 0 || i >= getsize(arg1))
  340.         xlerror("index out of range",arg2);
  341.     setelement(arg1,i,value);
  342.     xlpop();
  343.     }
  344.     else if (fun = xlgetprop(fun,s_setf))
  345.     setffunction(fun,place,value);
  346.     else
  347.     xlfail("bad place form");
  348. }
  349.  
  350. /* setffunction - call a user defined setf function */
  351. LOCAL setffunction(fun,place,value)
  352.   LVAL fun,place,value;
  353. {
  354.     LVAL *newfp;
  355.     int argc;
  356.  
  357.     /* create the new call frame */
  358.     newfp = xlsp;
  359.     pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
  360.     pusharg(fun);
  361.     pusharg(NIL);
  362.  
  363.     /* push the values of all of the place expressions and the new value */
  364.     for (argc = 1; consp(place); place = cdr(place), ++argc)
  365.     pusharg(xleval(car(place)));
  366.     pusharg(value);
  367.  
  368.     /* insert the argument count and establish the call frame */
  369.     newfp[2] = cvfixnum((FIXTYPE)argc);
  370.     xlfp = newfp;
  371.  
  372.     /* apply the function */
  373.     xlapply(argc);
  374. }
  375.                
  376. /* xdefun - special form 'defun' */
  377. LVAL xdefun()
  378. {
  379.     LVAL sym,fargs,arglist;
  380.  
  381.     /* get the function symbol and formal argument list */
  382.     xlsave1(arglist);
  383.     sym = xlgasymbol();
  384.     fargs = xlgalist();
  385.     arglist = makearglist(xlargc,xlargv);
  386.  
  387.     /* make the symbol point to a new function definition */
  388.     xlsetfunction(sym,xlclose(sym,s_lambda,fargs,arglist,xlenv,xlfenv));
  389.  
  390.     /* restore the stack and return the function symbol */
  391.     xlpop();
  392.     return (sym);
  393. }
  394.  
  395. /* xdefmacro - special form 'defmacro' */
  396. LVAL xdefmacro()
  397. {
  398.     LVAL sym,fargs,arglist;
  399.  
  400.     /* get the function symbol and formal argument list */
  401.     xlsave1(arglist);
  402.     sym = xlgasymbol();
  403.     fargs = xlgalist();
  404.     arglist = makearglist(xlargc,xlargv);
  405.  
  406.     /* make the symbol point to a new function definition */
  407.     xlsetfunction(sym,xlclose(sym,s_macro,fargs,arglist,NIL,NIL));
  408.  
  409.     /* restore the stack and return the function symbol */
  410.     xlpop();
  411.     return (sym);
  412. }
  413.  
  414. /* xcond - special form 'cond' */
  415. LVAL xcond()
  416. {
  417.     LVAL list,val;
  418.  
  419.     /* find a predicate that is true */
  420.     for (val = NIL; moreargs(); ) {
  421.  
  422.     /* get the next conditional */
  423.     list = nextarg();
  424.  
  425.     /* evaluate the predicate part */
  426.     if (consp(list) && (val = xleval(car(list)))) {
  427.  
  428.         /* evaluate each expression */
  429.         for (list = cdr(list); consp(list); list = cdr(list))
  430.         val = xleval(car(list));
  431.  
  432.         /* exit the loop */
  433.         break;
  434.     }
  435.     }
  436.  
  437.     /* return the value */
  438.     return (val);
  439. }
  440.  
  441. /* xwhen - special form 'when' */
  442. LVAL xwhen()
  443. {
  444.     LVAL val;
  445.  
  446.     /* check the test expression */
  447.     if (val = xleval(xlgetarg()))
  448.     while (moreargs())
  449.         val = xleval(nextarg());
  450.  
  451.     /* return the value */
  452.     return (val);
  453. }
  454.  
  455. /* xunless - special form 'unless' */
  456. LVAL xunless()
  457. {
  458.     LVAL val=NIL;
  459.  
  460.     /* check the test expression */
  461.     if (xleval(xlgetarg()) == NIL)
  462.     while (moreargs())
  463.         val = xleval(nextarg());
  464.  
  465.     /* return the value */
  466.     return (val);
  467. }
  468.  
  469. /* xcase - special form 'case' */
  470. LVAL xcase()
  471. {
  472.     LVAL key,list,cases,val;
  473.  
  474.     /* protect some pointers */
  475.     xlsave1(key);
  476.  
  477.     /* get the key expression */
  478.     key = xleval(nextarg());
  479.  
  480.     /* find a case that matches */
  481.     for (val = NIL; moreargs(); ) {
  482.  
  483.     /* get the next case clause */
  484.     list = nextarg();
  485.  
  486.     /* make sure this is a valid clause */
  487.     if (consp(list)) {
  488.  
  489.         /* compare the key list against the key */
  490.         if ((cases = car(list)) == true ||
  491.                 (listp(cases) && keypresent(key,cases)) ||
  492.                 eql(key,cases)) {
  493.  
  494.         /* evaluate each expression */
  495.         for (list = cdr(list); consp(list); list = cdr(list))
  496.             val = xleval(car(list));
  497.  
  498.         /* exit the loop */
  499.         break;
  500.         }
  501.     }
  502.     else
  503.         xlerror("bad case clause",list);
  504.     }
  505.  
  506.     /* restore the stack */
  507.     xlpop();
  508.  
  509.     /* return the value */
  510.     return (val);
  511. }
  512.  
  513. /* keypresent - check for the presence of a key in a list */
  514. LOCAL int keypresent(key,list)
  515.   LVAL key,list;
  516. {
  517.     for (; consp(list); list = cdr(list))
  518.     if (eql(car(list),key))
  519.         return (TRUE);
  520.     return (FALSE);
  521. }
  522.  
  523. /* xand - special form 'and' */
  524. LVAL xand()
  525. {
  526.     LVAL val;
  527.  
  528.     /* evaluate each argument */
  529.     for (val = true; moreargs(); )
  530.     if ((val = xleval(nextarg())) == NIL)
  531.         break;
  532.  
  533.     /* return the result value */
  534.     return (val);
  535. }
  536.  
  537. /* xor - special form 'or' */
  538. LVAL xor()
  539. {
  540.     LVAL val;
  541.  
  542.     /* evaluate each argument */
  543.     for (val = NIL; moreargs(); )
  544.     if ((val = xleval(nextarg())))
  545.         break;
  546.  
  547.     /* return the result value */
  548.     return (val);
  549. }
  550.  
  551. /* xif - special form 'if' */
  552. LVAL xif()
  553. {
  554.     LVAL testexpr,thenexpr,elseexpr;
  555.  
  556.     /* get the test expression, then clause and else clause */
  557.     testexpr = xlgetarg();
  558.     thenexpr = xlgetarg();
  559.     elseexpr = (moreargs() ? xlgetarg() : NIL);
  560.     xllastarg();
  561.  
  562.     /* evaluate the appropriate clause */
  563.     return (xleval(xleval(testexpr) ? thenexpr : elseexpr));
  564. }
  565.  
  566. /* xlet - special form 'let' */
  567. LVAL xlet()
  568. {
  569.     return (let(TRUE));
  570. }
  571.  
  572. /* xletstar - special form 'let*' */
  573. LVAL xletstar()
  574. {
  575.     return (let(FALSE));
  576. }
  577.  
  578. /* let - common let routine */
  579. LOCAL LVAL let(pflag)
  580.   int pflag;
  581. {
  582.     LVAL newenv,val;
  583.  
  584.     /* protect some pointers */
  585.     xlsave1(newenv);
  586.  
  587.     /* create a new environment frame */
  588.     newenv = xlframe(xlenv);
  589.  
  590.     /* get the list of bindings and bind the symbols */
  591.     if (!pflag) xlenv = newenv;
  592.     dobindings(xlgalist(),newenv);
  593.     if (pflag) xlenv = newenv;
  594.  
  595.     /* execute the code */
  596.     for (val = NIL; moreargs(); )
  597.     val = xleval(nextarg());
  598.  
  599.     /* unbind the arguments */
  600.     xlenv = cdr(xlenv);
  601.  
  602.     /* restore the stack */
  603.     xlpop();
  604.  
  605.     /* return the result */
  606.     return (val);
  607. }
  608.  
  609. /* xflet - built-in function 'flet' */
  610. LVAL xflet()
  611. {
  612.     return (flet(s_lambda,TRUE));
  613. }
  614.  
  615. /* xlabels - built-in function 'labels' */
  616. LVAL xlabels()
  617. {
  618.     return (flet(s_lambda,FALSE));
  619. }
  620.  
  621. /* xmacrolet - built-in function 'macrolet' */
  622. LVAL xmacrolet()
  623. {
  624.     return (flet(s_macro,TRUE));
  625. }
  626.  
  627. /* flet - common flet/labels/macrolet routine */
  628. LOCAL LVAL flet(type,letflag)
  629.   LVAL type; int letflag;
  630. {
  631.     LVAL list,bnd,sym,fargs,val;
  632.  
  633.     /* create a new environment frame */
  634.     xlfenv = xlframe(xlfenv);
  635.  
  636.     /* bind each symbol in the list of bindings */
  637.     for (list = xlgalist(); consp(list); list = cdr(list)) {
  638.  
  639.     /* get the next binding */
  640.     bnd = car(list);
  641.  
  642.     /* get the symbol and the function definition */
  643.     sym = match(SYMBOL,&bnd);
  644.     fargs = match(LIST,&bnd);
  645.     val = xlclose(sym,type,fargs,bnd,xlenv,(letflag?cdr(xlfenv):xlfenv));
  646.  
  647.     /* bind the value to the symbol */
  648.     xlfbind(sym,val);
  649.     }
  650.  
  651.     /* execute the code */
  652.     for (val = NIL; moreargs(); )
  653.     val = xleval(nextarg());
  654.  
  655.     /* unbind the arguments */
  656.     xlfenv = cdr(xlfenv);
  657.  
  658.     /* return the result */
  659.     return (val);
  660. }
  661.  
  662. /* xprog - special form 'prog' */
  663. LVAL xprog()
  664. {
  665.     return (prog(TRUE));
  666. }
  667.  
  668. /* xprogstar - special form 'prog*' */
  669. LVAL xprogstar()
  670. {
  671.     return (prog(FALSE));
  672. }
  673.  
  674. /* prog - common prog routine */
  675. LOCAL LVAL prog(pflag)
  676.   int pflag;
  677. {
  678.     LVAL newenv,val;
  679.     CONTEXT cntxt;
  680.  
  681.     /* protect some pointers */
  682.     xlsave1(newenv);
  683.  
  684.     /* create a new environment frame */
  685.     newenv = xlframe(xlenv);
  686.  
  687.     /* establish a new execution context */
  688.     xlbegin(&cntxt,CF_RETURN,NIL);
  689.     if (setjmp(cntxt.c_jmpbuf))
  690.     val = xlvalue;
  691.     else {
  692.  
  693.     /* get the list of bindings and bind the symbols */
  694.     if (!pflag) xlenv = newenv;
  695.     dobindings(xlgalist(),newenv);
  696.     if (pflag) xlenv = newenv;
  697.  
  698.     /* execute the code */
  699.     tagbody();
  700.     val = NIL;
  701.  
  702.     /* unbind the arguments */
  703.     xlenv = cdr(xlenv);
  704.     }
  705.     xlend(&cntxt);
  706.  
  707.     /* restore the stack */
  708.     xlpop();
  709.  
  710.     /* return the result */
  711.     return (val);
  712. }
  713.  
  714. /* xgo - special form 'go' */
  715. LVAL xgo()
  716. {
  717.     LVAL label;
  718.  
  719.     /* get the target label */
  720.     label = xlgetarg();
  721.     xllastarg();
  722.  
  723.     /* transfer to the label */
  724.     xlgo(label);
  725. }
  726.  
  727. /* xreturn - special form 'return' */
  728. LVAL xreturn()
  729. {
  730.     LVAL val;
  731.  
  732.     /* get the return value */
  733.     val = (moreargs() ? xleval(nextarg()) : NIL);
  734.     xllastarg();
  735.  
  736.     /* return from the inner most block */
  737.     xlreturn(NIL,val);
  738. }
  739.  
  740. /* xrtnfrom - special form 'return-from' */
  741. LVAL xrtnfrom()
  742. {
  743.     LVAL name,val;
  744.  
  745.     /* get the return value */
  746.     name = xlgasymbol();
  747.     val = (moreargs() ? xleval(nextarg()) : NIL);
  748.     xllastarg();
  749.  
  750.     /* return from the inner most block */
  751.     xlreturn(name,val);
  752. }
  753.  
  754. /* xprog1 - special form 'prog1' */
  755. LVAL xprog1()
  756. {
  757.     return (progx(1));
  758. }
  759.  
  760. /* xprog2 - special form 'prog2' */
  761. LVAL xprog2()
  762. {
  763.     return (progx(2));
  764. }
  765.  
  766. /* progx - common progx code */
  767. LOCAL LVAL progx(n)
  768.   int n;
  769. {
  770.     LVAL val;
  771.  
  772.     /* protect some pointers */
  773.     xlsave1(val);
  774.  
  775.     /* evaluate the first n expressions */
  776.     while (moreargs() && --n >= 0)
  777.     val = xleval(nextarg());
  778.  
  779.     /* evaluate each remaining argument */
  780.     while (moreargs())
  781.     xleval(nextarg());
  782.  
  783.     /* restore the stack */
  784.     xlpop();
  785.  
  786.     /* return the last test expression value */
  787.     return (val);
  788. }
  789.  
  790. /* xprogn - special form 'progn' */
  791. LVAL xprogn()
  792. {
  793.     LVAL val;
  794.  
  795.     /* evaluate each expression */
  796.     for (val = NIL; moreargs(); )
  797.     val = xleval(nextarg());
  798.  
  799.     /* return the last test expression value */
  800.     return (val);
  801. }
  802.  
  803. /* xprogv - special form 'progv' */
  804. LVAL xprogv()
  805. {
  806.     LVAL olddenv,vars,vals,val;
  807.  
  808.     /* protect some pointers */
  809.     xlstkcheck(2);
  810.     xlsave(vars);
  811.     xlsave(vals);
  812.  
  813.     /* get the list of variables and the list of values */
  814.     vars = xlgalist(); vars = xleval(vars);
  815.     vals = xlgalist(); vals = xleval(vals);
  816.  
  817.     /* bind the values to the variables */
  818.     for (olddenv = xldenv; consp(vars); vars = cdr(vars)) {
  819.     if (!symbolp(car(vars)))
  820.         xlerror("expecting a symbol",car(vars));
  821.     if (consp(vals)) {
  822.         xldbind(car(vars),car(vals));
  823.         vals = cdr(vals);
  824.     }
  825.     else
  826.         xldbind(car(vars),s_unbound);
  827.     }
  828.  
  829.     /* evaluate each expression */
  830.     for (val = NIL; moreargs(); )
  831.     val = xleval(nextarg());
  832.  
  833.     /* restore the previous environment and the stack */
  834.     xlunbind(olddenv);
  835.     xlpopn(2);
  836.  
  837.     /* return the last test expression value */
  838.     return (val);
  839. }
  840.  
  841. /* xloop - special form 'loop' */
  842. LVAL xloop()
  843. {
  844.     LVAL *argv,arg,val;
  845.     CONTEXT cntxt;
  846.     int argc;
  847.  
  848.     /* protect some pointers */
  849.     xlsave1(arg);
  850.  
  851.     /* establish a new execution context */
  852.     xlbegin(&cntxt,CF_RETURN,NIL);
  853.     if (setjmp(cntxt.c_jmpbuf))
  854.     val = xlvalue;
  855.     else
  856.     for (argv = xlargv, argc = xlargc; ; xlargv = argv, xlargc = argc)
  857.         while (moreargs()) {
  858.         arg = nextarg();
  859.         if (consp(arg))
  860.             xleval(arg);
  861.         }
  862.     xlend(&cntxt);
  863.  
  864.     /* restore the stack */
  865.     xlpop();
  866.  
  867.     /* return the result */
  868.     return (val);
  869. }
  870.  
  871. /* xdo - special form 'do' */
  872. LVAL xdo()
  873. {
  874.     return (doloop(TRUE));
  875. }
  876.  
  877. /* xdostar - special form 'do*' */
  878. LVAL xdostar()
  879. {
  880.     return (doloop(FALSE));
  881. }
  882.  
  883. /* doloop - common do routine */
  884. LOCAL LVAL doloop(pflag)
  885.   int pflag;
  886. {
  887.     LVAL newenv,*argv,blist,clist,test,val;
  888.     CONTEXT cntxt;
  889.     int argc;
  890.  
  891.     /* protect some pointers */
  892.     xlsave1(newenv);
  893.  
  894.     /* get the list of bindings, the exit test and the result forms */
  895.     blist = xlgalist();
  896.     clist = xlgalist();
  897.     test = (consp(clist) ? car(clist) : NIL);
  898.     argv = xlargv;
  899.     argc = xlargc;
  900.  
  901.     /* create a new environment frame */
  902.     newenv = xlframe(xlenv);
  903.  
  904.     /* establish a new execution context */
  905.     xlbegin(&cntxt,CF_RETURN,NIL);
  906.     if (setjmp(cntxt.c_jmpbuf))
  907.     val = xlvalue;
  908.     else {
  909.  
  910.     /* bind the symbols */
  911.     if (!pflag) xlenv = newenv;
  912.     dobindings(blist,newenv);
  913.     if (pflag) xlenv = newenv;
  914.  
  915.     /* execute the loop as long as the test is false */
  916.     for (val = NIL; xleval(test) == NIL; doupdates(blist,pflag)) {
  917.         xlargv = argv;
  918.         xlargc = argc;
  919.         tagbody();
  920.     }
  921.  
  922.     /* evaluate the result expression */
  923.     if (consp(clist))
  924.         for (clist = cdr(clist); consp(clist); clist = cdr(clist))
  925.         val = xleval(car(clist));
  926.  
  927.     /* unbind the arguments */
  928.     xlenv = cdr(xlenv);
  929.     }
  930.     xlend(&cntxt);
  931.  
  932.     /* restore the stack */
  933.     xlpop();
  934.  
  935.     /* return the result */
  936.     return (val);
  937. }
  938.  
  939. /* xdolist - special form 'dolist' */
  940. LVAL xdolist()
  941. {
  942.     LVAL list,*argv,clist,sym,val;
  943.     CONTEXT cntxt;
  944.     int argc;
  945.  
  946.     /* protect some pointers */
  947.     xlsave1(list);
  948.  
  949.     /* get the control list (sym list result-expr) */
  950.     clist = xlgalist();
  951.     sym = match(SYMBOL,&clist);
  952.     list = evmatch(LIST,&clist);
  953.     argv = xlargv;
  954.     argc = xlargc;
  955.  
  956.     /* initialize the local environment */
  957.     xlenv = xlframe(xlenv);
  958.     xlbind(sym,NIL);
  959.  
  960.     /* establish a new execution context */
  961.     xlbegin(&cntxt,CF_RETURN,NIL);
  962.     if (setjmp(cntxt.c_jmpbuf))
  963.     val = xlvalue;
  964.     else {
  965.  
  966.     /* loop through the list */
  967.     for (val = NIL; consp(list); list = cdr(list)) {
  968.  
  969.         /* bind the symbol to the next list element */
  970.         xlsetvalue(sym,car(list));
  971.  
  972.         /* execute the loop body */
  973.         xlargv = argv;
  974.         xlargc = argc;
  975.         tagbody();
  976.     }
  977.  
  978.     /* evaluate the result expression */
  979.     xlsetvalue(sym,NIL);
  980.     val = (consp(clist) ? xleval(car(clist)) : NIL);
  981.  
  982.     /* unbind the arguments */
  983.     xlenv = cdr(xlenv);
  984.     }
  985.     xlend(&cntxt);
  986.  
  987.     /* restore the stack */
  988.     xlpop();
  989.  
  990.     /* return the result */
  991.     return (val);
  992. }
  993.  
  994. /* xdotimes - special form 'dotimes' */
  995. LVAL xdotimes()
  996. {
  997.     LVAL *argv,clist,sym,cnt,val;
  998.     CONTEXT cntxt;
  999.     int argc,n,i;
  1000.  
  1001.     /* get the control list (sym list result-expr) */
  1002.     clist = xlgalist();
  1003.     sym = match(SYMBOL,&clist);
  1004.     cnt = evmatch(FIXNUM,&clist); n = getfixnum(cnt);
  1005.     argv = xlargv;
  1006.     argc = xlargc;
  1007.  
  1008.     /* initialize the local environment */
  1009.     xlenv = xlframe(xlenv);
  1010.     xlbind(sym,NIL);
  1011.  
  1012.     /* establish a new execution context */
  1013.     xlbegin(&cntxt,CF_RETURN,NIL);
  1014.     if (setjmp(cntxt.c_jmpbuf))
  1015.     val = xlvalue;
  1016.     else {
  1017.  
  1018.     /* loop through for each value from zero to n-1 */
  1019.     for (val = NIL, i = 0; i < n; ++i) {
  1020.  
  1021.         /* bind the symbol to the next list element */
  1022.         xlsetvalue(sym,cvfixnum((FIXTYPE)i));
  1023.  
  1024.         /* execute the loop body */
  1025.         xlargv = argv;
  1026.         xlargc = argc;
  1027.         tagbody();
  1028.     }
  1029.  
  1030.     /* evaluate the result expression */
  1031.     xlsetvalue(sym,cnt);
  1032.     val = (consp(clist) ? xleval(car(clist)) : NIL);
  1033.  
  1034.     /* unbind the arguments */
  1035.     xlenv = cdr(xlenv);
  1036.     }
  1037.     xlend(&cntxt);
  1038.  
  1039.     /* return the result */
  1040.     return (val);
  1041. }
  1042.  
  1043. /* xblock - special form 'block' */
  1044. LVAL xblock()
  1045. {
  1046.     LVAL name,val;
  1047.     CONTEXT cntxt;
  1048.  
  1049.     /* get the block name */
  1050.     name = xlgetarg();
  1051.     if (name && !symbolp(name))
  1052.     xlbadtype(name);
  1053.  
  1054.     /* execute the block */
  1055.     xlbegin(&cntxt,CF_RETURN,name);
  1056.     if (setjmp(cntxt.c_jmpbuf))
  1057.     val = xlvalue;
  1058.     else
  1059.     for (val = NIL; moreargs(); )
  1060.         val = xleval(nextarg());
  1061.     xlend(&cntxt);
  1062.  
  1063.     /* return the value of the last expression */
  1064.     return (val);
  1065. }
  1066.  
  1067. /* xtagbody - special form 'tagbody' */
  1068. LVAL xtagbody()
  1069. {
  1070.     tagbody();
  1071.     return (NIL);
  1072. }
  1073.  
  1074. /* xcatch - special form 'catch' */
  1075. LVAL xcatch()
  1076. {
  1077.     CONTEXT cntxt;
  1078.     LVAL tag,val;
  1079.  
  1080.     /* protect some pointers */
  1081.     xlsave1(tag);
  1082.  
  1083.     /* get the tag */
  1084.     tag = xleval(nextarg());
  1085.  
  1086.     /* establish an execution context */
  1087.     xlbegin(&cntxt,CF_THROW,tag);
  1088.  
  1089.     /* check for 'throw' */
  1090.     if (setjmp(cntxt.c_jmpbuf))
  1091.     val = xlvalue;
  1092.  
  1093.     /* otherwise, evaluate the remainder of the arguments */
  1094.     else {
  1095.     for (val = NIL; moreargs(); )
  1096.         val = xleval(nextarg());
  1097.     }
  1098.     xlend(&cntxt);
  1099.  
  1100.     /* restore the stack */
  1101.     xlpop();
  1102.  
  1103.     /* return the result */
  1104.     return (val);
  1105. }
  1106.  
  1107. /* xthrow - special form 'throw' */
  1108. LVAL xthrow()
  1109. {
  1110.     LVAL tag,val;
  1111.  
  1112.     /* get the tag and value */
  1113.     tag = xleval(nextarg());
  1114.     val = (moreargs() ? xleval(nextarg()) : NIL);
  1115.     xllastarg();
  1116.  
  1117.     /* throw the tag */
  1118.     xlthrow(tag,val);
  1119. }
  1120.  
  1121. /* xunwindprotect - special form 'unwind-protect' */
  1122. LVAL xunwindprotect()
  1123. {
  1124.     extern CONTEXT *xltarget;
  1125.     extern int xlmask;
  1126.     CONTEXT cntxt,*target;
  1127.     int mask,sts;
  1128.     LVAL val;
  1129.  
  1130.     /* protect some pointers */
  1131.     xlsave1(val);
  1132.  
  1133.     /* get the expression to protect */
  1134.     val = xlgetarg();
  1135.  
  1136.     /* evaluate the protected expression */
  1137.     xlbegin(&cntxt,CF_UNWIND,NIL);
  1138.     if (sts = setjmp(cntxt.c_jmpbuf)) {
  1139.     target = xltarget;
  1140.     mask = xlmask;
  1141.     val = xlvalue;
  1142.     }
  1143.     else
  1144.     val = xleval(val);
  1145.     xlend(&cntxt);
  1146.     
  1147.     /* evaluate the cleanup expressions */
  1148.     while (moreargs())
  1149.     xleval(nextarg());
  1150.  
  1151.     /* if unwinding, continue unwinding */
  1152.     if (sts)
  1153.     xljump(target,mask,val);
  1154.  
  1155.     /* restore the stack */
  1156.     xlpop();
  1157.  
  1158.     /* return the value of the protected expression */
  1159.     return (val);
  1160. }
  1161.  
  1162. /* xerrset - special form 'errset' */
  1163. LVAL xerrset()
  1164. {
  1165.     LVAL expr,flag,val;
  1166.     CONTEXT cntxt;
  1167.  
  1168.     /* get the expression and the print flag */
  1169.     expr = xlgetarg();
  1170.     flag = (moreargs() ? xlgetarg() : true);
  1171.     xllastarg();
  1172.  
  1173.     /* establish an execution context */
  1174.     xlbegin(&cntxt,CF_ERROR,flag);
  1175.  
  1176.     /* check for error */
  1177.     if (setjmp(cntxt.c_jmpbuf))
  1178.     val = NIL;
  1179.  
  1180.     /* otherwise, evaluate the expression */
  1181.     else {
  1182.     expr = xleval(expr);
  1183.     val = consa(expr);
  1184.     }
  1185.     xlend(&cntxt);
  1186.  
  1187.     /* return the result */
  1188.     return (val);
  1189. }
  1190.  
  1191. /* xtrace - special form 'trace' */
  1192. LVAL xtrace()
  1193. {
  1194.     LVAL sym,fun,this;
  1195.  
  1196.     /* loop through all of the arguments */
  1197.     sym = xlenter("*TRACELIST*");
  1198.     while (moreargs()) {
  1199.     fun = xlgasymbol();
  1200.  
  1201.     /* check for the function name already being in the list */
  1202.     for (this = getvalue(sym); consp(this); this = cdr(this))
  1203.         if (car(this) == fun)
  1204.         break;
  1205.  
  1206.     /* add the function name to the list */
  1207.     if (null(this))
  1208.         setvalue(sym,cons(fun,getvalue(sym)));
  1209.     }
  1210.     return (getvalue(sym));
  1211. }
  1212.  
  1213. /* xuntrace - special form 'untrace' */
  1214. LVAL xuntrace()
  1215. {
  1216.     LVAL sym,fun,this,last;
  1217.  
  1218.     /* loop through all of the arguments */
  1219.     sym = xlenter("*TRACELIST*");
  1220.     while (moreargs()) {
  1221.     fun = xlgasymbol();
  1222.  
  1223.     /* remove the function name from the list */
  1224.     last = NIL;
  1225.     for (this = getvalue(sym); consp(this); this = cdr(this)) {
  1226.         if (car(this) == fun) {
  1227.         if (last)
  1228.             rplacd(last,cdr(this));
  1229.         else
  1230.             setvalue(sym,cdr(this));
  1231.         break;
  1232.         }
  1233.         last = this;
  1234.     }
  1235.     }
  1236.     return (getvalue(sym));
  1237. }
  1238.  
  1239. /* dobindings - handle bindings for let/let*, prog/prog*, do/do* */
  1240. LOCAL dobindings(list,env)
  1241.   LVAL list,env;
  1242. {
  1243.     LVAL bnd,sym,val;
  1244.  
  1245.     /* protect some pointers */
  1246.     xlsave1(val);
  1247.  
  1248.     /* bind each symbol in the list of bindings */
  1249.     for (; consp(list); list = cdr(list)) {
  1250.  
  1251.     /* get the next binding */
  1252.     bnd = car(list);
  1253.  
  1254.     /* handle a symbol */
  1255.     if (symbolp(bnd)) {
  1256.         sym = bnd;
  1257.         val = NIL;
  1258.     }
  1259.  
  1260.     /* handle a list of the form (symbol expr) */
  1261.     else if (consp(bnd)) {
  1262.         sym = match(SYMBOL,&bnd);
  1263.         val = evarg(&bnd);
  1264.     }
  1265.     else
  1266.         xlfail("bad binding");
  1267.  
  1268.     /* bind the value to the symbol */
  1269.     xlpbind(sym,val,env);
  1270.     }
  1271.  
  1272.     /* restore the stack */
  1273.     xlpop();
  1274. }
  1275.  
  1276. /* doupdates - handle updates for do/do* */
  1277. LOCAL doupdates(list,pflag)
  1278.   LVAL list; int pflag;
  1279. {
  1280.     LVAL plist,bnd,sym,val;
  1281.  
  1282.     /* protect some pointers */
  1283.     xlstkcheck(2);
  1284.     xlsave(plist);
  1285.     xlsave(val);
  1286.  
  1287.     /* bind each symbol in the list of bindings */
  1288.     for (; consp(list); list = cdr(list)) {
  1289.  
  1290.     /* get the next binding */
  1291.     bnd = car(list);
  1292.  
  1293.     /* handle a list of the form (symbol expr) */
  1294.     if (consp(bnd)) {
  1295.         sym = match(SYMBOL,&bnd);
  1296.         bnd = cdr(bnd);
  1297.         if (bnd) {
  1298.         val = evarg(&bnd);
  1299.         if (pflag)
  1300.             plist = cons(cons(sym,val),plist);
  1301.         else
  1302.             xlsetvalue(sym,val);
  1303.         }
  1304.     }
  1305.     }
  1306.  
  1307.     /* set the values for parallel updates */
  1308.     for (; plist; plist = cdr(plist))
  1309.     xlsetvalue(car(car(plist)),cdr(car(plist)));
  1310.  
  1311.     /* restore the stack */
  1312.     xlpopn(2);
  1313. }
  1314.  
  1315. /* tagbody - execute code within a block and tagbody */
  1316. LOCAL tagbody()
  1317. {
  1318.     LVAL *argv,arg;
  1319.     CONTEXT cntxt;
  1320.     int argc;
  1321.  
  1322.     /* establish an execution context */
  1323.     xlbegin(&cntxt,CF_GO,NIL);
  1324.     argc = xlargc;
  1325.     argv = xlargv;
  1326.  
  1327.     /* check for a 'go' */
  1328.     if (setjmp(cntxt.c_jmpbuf)) {
  1329.     cntxt.c_xlargc = argc;
  1330.     cntxt.c_xlargv = argv;
  1331.     }
  1332.  
  1333.     /* execute the body */
  1334.     while (moreargs()) {
  1335.     arg = nextarg();
  1336.     if (consp(arg))
  1337.         xleval(arg);
  1338.     }
  1339.     xlend(&cntxt);
  1340. }
  1341.  
  1342. /* match - get an argument and match its type */
  1343. LOCAL LVAL match(type,pargs)
  1344.   int type; LVAL *pargs;
  1345. {
  1346.     LVAL arg;
  1347.  
  1348.     /* make sure the argument exists */
  1349.     if (!consp(*pargs))
  1350.     toofew(*pargs);
  1351.  
  1352.     /* get the argument value */
  1353.     arg = car(*pargs);
  1354.  
  1355.     /* move the argument pointer ahead */
  1356.     *pargs = cdr(*pargs);
  1357.  
  1358.     /* check its type */
  1359.     if (type == LIST) {
  1360.     if (arg && ntype(arg) != CONS)
  1361.         xlerror("bad argument type",arg);
  1362.     }
  1363.     else {
  1364.     if (arg == NIL || ntype(arg) != type)
  1365.         xlerror("bad argument type",arg);
  1366.     }
  1367.  
  1368.     /* return the argument */
  1369.     return (arg);
  1370. }
  1371.  
  1372. /* evarg - get the next argument and evaluate it */
  1373. LOCAL LVAL evarg(pargs)
  1374.   LVAL *pargs;
  1375. {
  1376.     LVAL arg;
  1377.  
  1378.     /* protect some pointers */
  1379.     xlsave1(arg);
  1380.  
  1381.     /* make sure the argument exists */
  1382.     if (!consp(*pargs))
  1383.     toofew(*pargs);
  1384.  
  1385.     /* get the argument value */
  1386.     arg = car(*pargs);
  1387.  
  1388.     /* move the argument pointer ahead */
  1389.     *pargs = cdr(*pargs);
  1390.  
  1391.     /* evaluate the argument */
  1392.     arg = xleval(arg);
  1393.  
  1394.     /* restore the stack */
  1395.     xlpop();
  1396.  
  1397.     /* return the argument */
  1398.     return (arg);
  1399. }
  1400.  
  1401. /* evmatch - get an evaluated argument and match its type */
  1402. LOCAL LVAL evmatch(type,pargs)
  1403.   int type; LVAL *pargs;
  1404. {
  1405.     LVAL arg;
  1406.  
  1407.     /* protect some pointers */
  1408.     xlsave1(arg);
  1409.  
  1410.     /* make sure the argument exists */
  1411.     if (!consp(*pargs))
  1412.     toofew(*pargs);
  1413.  
  1414.     /* get the argument value */
  1415.     arg = car(*pargs);
  1416.  
  1417.     /* move the argument pointer ahead */
  1418.     *pargs = cdr(*pargs);
  1419.  
  1420.     /* evaluate the argument */
  1421.     arg = xleval(arg);
  1422.  
  1423.     /* check its type */
  1424.     if (type == LIST) {
  1425.     if (arg && ntype(arg) != CONS)
  1426.         xlerror("bad argument type",arg);
  1427.     }
  1428.     else {
  1429.     if (arg == NIL || ntype(arg) != type)
  1430.         xlerror("bad argument type",arg);
  1431.     }
  1432.  
  1433.     /* restore the stack */
  1434.     xlpop();
  1435.  
  1436.     /* return the argument */
  1437.     return (arg);
  1438. }
  1439.  
  1440. /* toofew - too few arguments */
  1441. LOCAL toofew(args)
  1442.   LVAL args;
  1443. {
  1444.     xlerror("too few arguments",args);
  1445. }
  1446.  
  1447. /* toomany - too many arguments */
  1448. LOCAL toomany(args)
  1449.   LVAL args;
  1450. {
  1451.     xlerror("too many arguments",args);
  1452. }
  1453.  
  1454.